package com.xkw.autocode.code;

import java.io.File;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.xkw.autocode.PropertiesConfig;
import com.xkw.autocode.jdbc.entity.ColumnEntity;
import com.xkw.autocode.jdbc.entity.TableEntity;
import com.xkw.autocode.jdbc.mysql.MysqlSqlParser;
import com.xkw.autocode.service.TemplateConfigDetailService;
import com.xkw.autocode.util.FileUtils;
import com.xkw.autocode.util.MyDateUtils;
import com.xkw.autocode.util.ZipCompressor;
import com.xkw.autocode.vo.TemplateConfigDetailVo;
import com.xkw.autocode.web.codeexport.ao.CodeExportAo;

@Service
public class CodeExportService {

	private static Logger logger = LoggerFactory.getLogger(CodeExportService.class);

	@Autowired
	private CodeExportAo codeExportAo;

	@Autowired
	private TemplateConfigDetailService templateConfigDetailService;

	@Autowired
	private PropertiesConfig propertiesConfig;

	public String doExport(Long dbId, String sqlContent, String tableNames, Long templateId, String basePakeage) {
		return doExport(dbId, sqlContent, tableNames, templateId, basePakeage, true);
	}

	public String doExport(Long dbId, String sqlContent, String tableNames, Long templateId, String basePakeage,
			boolean iszip) {

		// 获取表格的信息
		List<TableEntity> tables = this.getTables(dbId, sqlContent, tableNames);
		if (tables == null) {
			return null;
		}

		// 查询所有的模板
		List<TemplateConfigDetailVo> templateFiles = templateConfigDetailService.findByTemplateId(templateId);

		// 输出路径
		String outPath = getOutPath(dbId);

		for (TableEntity table : tables) {

			// 构造模板中需要用到的关键字
			Map<String, String> map = getKeywordsMap(table, basePakeage);

			for (TemplateConfigDetailVo templateFile : templateFiles) {

				try {

					// 读取模板内容
					StringBuilder sbl = new StringBuilder(templateFile.getTemplateContent());

					// 输出文件的全路径
					StringBuilder pathSbl = new StringBuilder();
					pathSbl.append(outPath).append(File.separator);
					pathSbl.append(basePakeage.replace(".", File.separator)).append(File.separator);
					if (StringUtils.isNotEmpty(templateFile.getTemplatePath())) {
						pathSbl.append(templateFile.getTemplatePath().replace(".", File.separator))
								.append(File.separator);
					}
					pathSbl.append(templateFile.getTemplateFileName());

					String outFullPath = pathSbl.toString();
					if (outFullPath.indexOf('{') != -1) {
						outFullPath = this.replaceLine(map, outFullPath);
					}

					FileUtils.writeToFile(outFullPath, this.replaceLine(map, sbl.toString()));
				} catch (Exception e) {
					logger.error("", e);
				}
			}
		}

		// 压缩文件
		if (iszip) {
			String zipFilePath = outPath + ".zip";
			ZipCompressor compress = new ZipCompressor(zipFilePath);
			compress.compress(outPath);

			// 删除文件
			FileUtils.deleteFile(outPath);

			return zipFilePath;
		} else {
			return outPath;
		}
	}

	// 封装模板中需要用到的关键字
	public Map<String, String> getKeywordsMap(TableEntity table, String basePakeage) {
		Map<String, String> map = new LinkedHashMap<>();

		// 表名
		map.put("Table_Name", table.getTableName());
		// 表注释
		map.put("Table_Comment", table.getComments());

		// 包路径
		map.put("Base_Pakeage", basePakeage);

		String className = CodeUtils.getClassName(table.getTableName());

		// 类名(大驼峰)
		map.put("Class_Name_BigHump", className);

		// 类名(小驼峰)
		map.put("Class_Name_SmallHump", CodeUtils.getLowAttr(className));

		// 类名(全小写)
		map.put("Class_Name_Lowercase", className.toLowerCase());
		// 类名(全大写)
		map.put("Class_Name_Uppercase", className.toUpperCase());
		
		List<ColumnEntity> columns = table.getColumns();

		MybatisTemplateUtils.setMybatisXmlProperty(columns, map);

		map.put("GetSet_Properties", JavaTemplateUtils.getJavaProperty(columns,1));
		map.put("GetSet_Properties2", JavaTemplateUtils.getJavaProperty(columns,2));
		map.put("GetSet_Properties3", JavaTemplateUtils.getJavaProperty(columns,3));
		map.put("GetSet_Properties4", JavaTemplateUtils.getJavaProperty(columns,4));
		map.put("GetSet_Properties5", JavaTemplateUtils.getJavaProperty(columns,5));
		map.put("GetSet_Properties6", JavaTemplateUtils.getJavaProperty(columns,6));
		map.put("GetSet_Properties7", JavaTemplateUtils.getJavaProperty(columns,7));
		
		map.put("GetSet_Method", JavaTemplateUtils.getJavaPropertyGetSet(columns));

		map.put("Html_Table_Title", HtmlTemplateUtils.getThHtml(columns));
		map.put("Html_Table_Content", HtmlTemplateUtils.getDatatableScript(columns));
		
		map.put("Vue_Conditions", VueTemplateUtils.getConditions(columns));
		map.put("Vue_TableThead", VueTemplateUtils.getTableThead(columns));
		map.put("Vue_TableColumn", VueTemplateUtils.getTableColumn(columns));
		map.put("Vue_Table", VueTemplateUtils.getTable(columns));
		map.put("Vue_FormData", VueTemplateUtils.getFormData(columns));

		return map;
	}

	private List<TableEntity> getTables(Long dbId, String sqlContent, String tableNames) {
		// 获取表格的信息
		List<TableEntity> tables = null;
		if (dbId != null) {
			tables = codeExportAo.queryTables(dbId, true, tableNames);
		} else if (sqlContent != null) {
			tables = new MysqlSqlParser().getTableFromSql(sqlContent, tableNames);
		}
		return tables;
	}

	private String getOutPath(Long dbId) {
		if (dbId == null) {
			dbId = 0L;
		}
		// 输出路径
		String outPath = propertiesConfig.getCodeTemplateDir() + File.separator + "out" + File.separator
				+ MyDateUtils.formatDateTime(MyDateUtils.DATA_FORMAT1, new Date()) + "_" + dbId;
		File file = new File(outPath);
		if (file.exists()) {
			FileUtils.deleteFile(file);
		}
		return outPath;
	}

	private String replaceLine(Map<String, String> map, String line) {
		if (line.trim().length() == 0) {
			return line;
		}

		for (Map.Entry<String, String> entry : map.entrySet()) {
			String key = entry.getKey();
			String value = entry.getValue();
			if (line.indexOf(key) == -1 || value == null) {
				continue;
			}

			try {
				if (key.equals("html_list_table_content")) {
					line = line.replace("{" + key + "}", value);
				} else {
					line = line.replaceAll("\\{" + key + "\\}", value);
				}
			} catch (Exception e) {
				logger.error(line + "\n" + key + "=" + value, e);
			}
		}

		return line;
	}
}
